using Net35.Xrm.Sdk.Client;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.Serialization;
namespace Net35.Xrm.Sdk
{
	[DataContract(Name = "Entity", Namespace = "http://schemas.microsoft.com/xrm/2011/Contracts")]
	public class Entity : IExtensibleDataObject
	{
		private string _logicalName;
		private Guid _id;
		private AttributeCollection _attributes;
		private EntityState? _entityState;
		private FormattedValueCollection _formattedValues;
		private RelatedEntityCollection _relatedEntities;
		internal bool _isReadOnly;
		private ExtensionDataObject _extensionDataObject;
		[DataMember]
		public string LogicalName
		{
			get
			{
				return this._logicalName;
			}
			set
			{
				this.CheckIsReadOnly("LogicalName");
				this._logicalName = value;
			}
		}
		[DataMember]
		public virtual Guid Id
		{
			get
			{
				return this._id;
			}
			set
			{
				if (this._id != Guid.Empty)
				{
					this.CheckIsReadOnly("Id");
				}
				this._id = value;
			}
		}
		[DataMember]
		public AttributeCollection Attributes
		{
			get
			{
				if (this._attributes == null)
				{
					this._attributes = new AttributeCollection();
				}
				return this._attributes;
			}
			set
			{
				this._attributes = value;
			}
		}
		[DataMember]
		public EntityState? EntityState
		{
			get
			{
				return this._entityState;
			}
			set
			{
				this.CheckIsReadOnly("EntityState");
				this._entityState = value;
			}
		}
		[DataMember]
		public FormattedValueCollection FormattedValues
		{
			get
			{
				if (this._formattedValues == null)
				{
					this._formattedValues = new FormattedValueCollection();
				}
				return this._formattedValues;
			}
			internal set
			{
				this._formattedValues = value;
			}
		}
		[DataMember]
		public RelatedEntityCollection RelatedEntities
		{
			get
			{
				if (this._relatedEntities == null)
				{
					this._relatedEntities = new RelatedEntityCollection();
					this._relatedEntities.IsReadOnly = this.IsReadOnly;
				}
				return this._relatedEntities;
			}
			internal set
			{
				this.CheckIsReadOnly("RelatedEntities");
				this._relatedEntities = value;
			}
		}
		public object this[string attributeName]
		{
			get
			{
				return this.Attributes[attributeName];
			}
			set
			{
				this.Attributes[attributeName] = value;
			}
		}
		internal bool IsReadOnly
		{
			get
			{
				return this._isReadOnly;
			}
			set
			{
				this._isReadOnly = value;
				this.RelatedEntities.IsReadOnly = value;
			}
		}
		public ExtensionDataObject ExtensionData
		{
			get
			{
				return this._extensionDataObject;
			}
			set
			{
				this._extensionDataObject = value;
			}
		}
		public Entity() : this(null)
		{
		}
		public Entity(string entityName)
		{
			this._logicalName = entityName;
		}
		public bool Contains(string attributeName)
		{
			return this.Attributes.Contains(attributeName);
		}
		public T ToEntity<T>() where T : Entity
		{
			if (typeof(T) == typeof(Entity))
			{
				Entity entity = new Entity();
				this.ShallowCopyTo(entity);
				return entity as T;
			}
			if (StringExtensions.IsNullOrWhiteSpace(this._logicalName))
			{
				throw new NotSupportedException("LogicalName must be set before calling ToEntity()");
			}
			string text = null;
			object[] customAttributes = typeof(T).GetCustomAttributes(typeof(EntityLogicalNameAttribute), true);
			if (customAttributes != null)
			{
				object[] array = customAttributes;
				int num = 0;
				if (num < array.Length)
				{
					EntityLogicalNameAttribute entityLogicalNameAttribute = (EntityLogicalNameAttribute)array[num];
					text = entityLogicalNameAttribute.LogicalName;
				}
			}
			if (StringExtensions.IsNullOrWhiteSpace(text))
			{
				throw new NotSupportedException("Cannot convert to type that is does not have EntityLogicalNameAttribute");
			}
			if (this._logicalName != text)
			{
				throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Cannot convert entity {0} to {1}", new object[]
				{
					this._logicalName,
					text
				}));
			}
			T t = (T)((object)Activator.CreateInstance(typeof(T)));
			this.ShallowCopyTo(t);
			return t;
		}
		public EntityReference ToEntityReference()
		{
			return new EntityReference(this.LogicalName, this.Id);
		}
		internal void ShallowCopyTo(Entity target)
		{
			if (target != null && target != this)
			{
				target.Id = this.Id;
				target.SetLogicalNameInternal(this.LogicalName);
				target.SetEntityStateInternal(this.EntityState);
				target.SetRelatedEntitiesInternal(this.RelatedEntities);
				target.Attributes = this.Attributes;
				target.FormattedValues = this.FormattedValues;
				target.ExtensionData = this.ExtensionData;
			}
		}
		public virtual T GetAttributeValue<T>(string attributeLogicalName)
		{
			object attributeValue = this.GetAttributeValue(attributeLogicalName);
			if (attributeValue == null)
			{
				return default(T);
			}
			return (T)((object)attributeValue);
		}
		private object GetAttributeValue(string attributeLogicalName)
		{
			if (StringExtensions.IsNullOrWhiteSpace(attributeLogicalName))
			{
				throw new ArgumentNullException("attributeLogicalName");
			}
			if (!this.Contains(attributeLogicalName))
			{
				return null;
			}
			return this[attributeLogicalName];
		}
		protected virtual void SetAttributeValue(string attributeLogicalName, object value)
		{
			if (StringExtensions.IsNullOrWhiteSpace(attributeLogicalName))
			{
				throw new ArgumentNullException("attributeLogicalName");
			}
			this[attributeLogicalName] = value;
		}
		protected virtual string GetFormattedAttributeValue(string attributeLogicalName)
		{
			if (StringExtensions.IsNullOrWhiteSpace(attributeLogicalName))
			{
				throw new ArgumentNullException("attributeLogicalName");
			}
			if (!this.FormattedValues.Contains(attributeLogicalName))
			{
				return null;
			}
			return this.FormattedValues[attributeLogicalName];
		}
		protected virtual TEntity GetRelatedEntity<TEntity>(string relationshipSchemaName, EntityRole? primaryEntityRole) where TEntity : Entity
		{
			if (StringExtensions.IsNullOrWhiteSpace(relationshipSchemaName))
			{
				throw new ArgumentNullException("relationshipSchemaName");
			}
			Relationship key = new Relationship(relationshipSchemaName)
			{
				PrimaryEntityRole = primaryEntityRole
			};
			if (!this.RelatedEntities.Contains(key))
			{
				return default(TEntity);
			}
			return (TEntity)((object)this.RelatedEntities[key].Entities.FirstOrDefault<Entity>());
		}
		protected virtual void SetRelatedEntity<TEntity>(string relationshipSchemaName, EntityRole? primaryEntityRole, TEntity entity) where TEntity : Entity
		{
			if (StringExtensions.IsNullOrWhiteSpace(relationshipSchemaName))
			{
				throw new ArgumentNullException("relationshipSchemaName");
			}
			if (entity != null && StringExtensions.IsNullOrWhiteSpace(entity.LogicalName))
			{
				throw new ArgumentException("The entity is missing a value for the 'LogicalName' property.", "entity");
			}
			Relationship key = new Relationship(relationshipSchemaName)
			{
				PrimaryEntityRole = primaryEntityRole
			};
			EntityCollection entityCollection = (entity != null) ? new EntityCollection((IList<Entity>)new TEntity[]
			{
				entity
			})
			{
				EntityName = entity.LogicalName
			} : null;
			if (entityCollection != null)
			{
				this.RelatedEntities[key] = entityCollection;
				return;
			}
			this.RelatedEntities.Remove(key);
		}
		protected virtual IEnumerable<TEntity> GetRelatedEntities<TEntity>(string relationshipSchemaName, EntityRole? primaryEntityRole) where TEntity : Entity
		{
			if (StringExtensions.IsNullOrWhiteSpace(relationshipSchemaName))
			{
				throw new ArgumentNullException("relationshipSchemaName");
			}
			Relationship key = new Relationship(relationshipSchemaName)
			{
				PrimaryEntityRole = primaryEntityRole
			};
			if (!this.RelatedEntities.Contains(key))
			{
				return null;
			}
			return this.RelatedEntities[key].Entities.Cast<TEntity>();
		}
		protected virtual void SetRelatedEntities<TEntity>(string relationshipSchemaName, EntityRole? primaryEntityRole, IEnumerable<TEntity> entities) where TEntity : Entity
		{
			if (StringExtensions.IsNullOrWhiteSpace(relationshipSchemaName))
			{
				throw new ArgumentNullException("relationshipSchemaName");
			}
			if (entities != null && entities.Any((TEntity entity) => StringExtensions.IsNullOrWhiteSpace(entity.LogicalName)))
			{
				throw new ArgumentException("An entity is missing a value for the 'LogicalName' property.", "entities");
			}
			Relationship key = new Relationship(relationshipSchemaName)
			{
				PrimaryEntityRole = primaryEntityRole
			};
			EntityCollection arg_78_0;
			if (entities == null)
			{
				arg_78_0 = null;
			}
			else
			{
				EntityCollection entityCollection = new EntityCollection(new List<Entity>(entities.Select(e => e as Entity)));
				EntityCollection arg_72_0 = entityCollection;
				TEntity tEntity = entities.First<TEntity>();
				arg_72_0.EntityName = tEntity.LogicalName;
				arg_78_0 = entityCollection;
			}
			EntityCollection entityCollection2 = arg_78_0;
			if (entityCollection2 != null)
			{
				this.RelatedEntities[key] = entityCollection2;
				return;
			}
			this.RelatedEntities.Remove(key);
		}
		internal void SetLogicalNameInternal(string logicalName)
		{
			this._logicalName = logicalName;
		}
		internal void SetEntityStateInternal(EntityState? entityState)
		{
			this._entityState = entityState;
		}
		internal void SetRelatedEntitiesInternal(RelatedEntityCollection relatedEntities)
		{
			this._relatedEntities = relatedEntities;
		}
		private void CheckIsReadOnly(string propertyName)
		{
			if (this.IsReadOnly)
			{
				throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The entity is read-only and the '{0}' property cannot be modified. Use the context to update the entity instead.", new object[]
				{
					propertyName
				}));
			}
		}
	}
}
